unit oSimulationRenderer;

{
	created   26.3.2010
	author   	Miroslav Mintal
	purpose
}

interface

uses
   Windows, ComCtrls, Types, SysUtils, Dialogs, oManager, oProcessItem,
   OProcessObjectConstants, oFrameLL, oFormLL, oProject, oLevel, Vector,
   Generics.Collections, oLogicalEntity, oPolygon, Obstacle, oCoordinates,
   oFrameScene, oPhysicalEntity, oEntityTypeConstants,
    Path, oFormSimulation, oArrivalsManager, oRunPropertiesManager,
    oSimulation, Forms, oStatisticEventConstants, oStatisticProcessor,
    oPedestrian, Pedestrian, oFrameProgress, oMatrixCreating;

type
  ESimulationRenderer = class(Exception)
  end;

  TSimulationRenderer = class(TManager)
    strict private
      aGUI: TSimGUI;
      aName: string;
      aEntityId : integer;
      aEditorFrame: Tfeditor;
      aEditorProgress: TFrameProgress;
      aEditing : boolean;
      aLevel : Tlevel;
      aStatPath : string;
      aSimulation : TPedSimulation;
      aMain : TForm;
      aPause, aStop, aStarted: Boolean;
      properties: TRunPropertiesManager.TRunPropertiesType;
      actRep: Integer;
      procedure show;
      procedure DoSomeSimulation;
      procedure start;
      procedure pause;
      procedure stop;
    public
      constructor create(paMaster: TManager);
      function ProcessObject(paItem: TProcessItem):TProcessItem; override;
      property StatisticPath : string read aStatPath write aStatPath;
      property Simulation: TPedSimulation read aSimulation write aSimulation;
      property Form: TForm read aMain write aMain;
      property SimGUI: TSimGUI read aGUI;
  end;

implementation

uses
  fMain, oProcessObjects, oMasterManager, oCellularMotion;

resourcestring simFinished = 'simulation finished';
resourcestring simStopped = 'simulation stopped';

resourcestring calculating = 'currently calculated arrival: ';


procedure TSimulationRenderer.DoSomeSimulation;
var
   list: TProcessingList;
   i: Integer;
   arr : TArrivalsManager.TArrivalType;
   item : TPRocessItem;
   level: Tlevel;
   f : text;
begin
  repeat
    aPause := false;
    if aStarted
      then  Simulation.Simulation
      else Simulation.Continue;
    if (not aStop) and (not aPause)
      then begin
        aStarted := true;
        for arr in (Form as TfrmMain).Master.ArrivalsManager.Arrivals do
         if arr.StatPeople <> nil then
           Simulation.writeStaticticEvent(SE_PEOPLE_IN_ARRIVAL, arr.Name, arr.StatPeople.Value);
        Simulation.writeStaticticEvent(SE_PEOPLE_IN_MODEL, Simulation.StatPeopleInModel.Mean,Simulation.StatPeopleInModel.Dispersion);
        Simulation.closeStatFiles;
        (Form as TfrmMain).Master.SceneManager.Scene.ClearPedestrians;
        aEditorProgress.pgbSimulation.Position := aEditorProgress.pgbSimulation.Position + 1;
        aEditorProgress.pgbReplication.Position := 0;
        aSimulation.Free;
        Inc(actRep);
        aStop := false;
        aPause := false;
        Simulation := TPedSimulation.Create((Form as TfrmMain).Master.SceneManager.Scene,
                                            (Form as TfrmMain).Master.ArrivalsManager.Arrivals,
                                            properties,SimGUI);
        (Form as TfrmMain).Master.ProcessObject(TProcessItem.create(PO_ARRMAN_ACTIVATE,nil));
        if not DirectoryExists(StatisticPath + '\replication' + IntToStr(actRep)) then
          MkDir(StatisticPath + '\replication' + IntToStr(actRep));
        Simulation.StatisticDir := StatisticPath + '\replication' + IntToStr(actRep);
        Simulation.prepareStatFiles(properties.Stats, TStatisticProcessor.getStatisticTypes);
      end;
  until not((actRep < round(properties.Replications)) and not(aStop) and not(aPause));;

  if (aStop) or (actRep = round(properties.Replications))
    then begin
      aEditorProgress.pgbSimulation.Position := aEditorProgress.pgbSimulation.Max;
      if not aStop
        then MessageDlg(simFinished,mtInformation,[mbOK],0)
        else MessageDlg(simStopped,mtInformation,[mbOK],0);
      Simulation.closeStatFiles;
      Simulation.Free;
      Simulation := nil;
      list := TProcessingList.Create;
      list.addParameter(TInteger.Create(round(properties.Replications)));
      list.addParameter(TString.Create(StatisticPath));
      list.addParameter(TProcessingBoolList.Create(properties.Stats));
      list.addParameter(TProcessingForm.Create(Form));
      (Form as TfrmMain).Master.ProcessObject(TProcessItem.create(PO_EDITOR_STAT_SET_PARAMS, list));
      aStop := false;
      aPause := false;
    end;
end;

procedure TSimulationRenderer.pause;
begin
  if (not self.aPause) then
  begin
    aPause := true;
    aSimulation.StopSim;
  end
  else
  begin
    aPause := false;
    aStarted := false;    DoSomeSimulation;
  end;
end;

function TSimulationRenderer.ProcessObject(paItem: TProcessItem): TProcessItem;
var
   suc, ret : Boolean;
   form1 : TformSimulation;
   list : TProcessingList;
begin
    ret := false;
    suc := false;
    if paItem.Data is TProcessingList then
      list := TProcessingList(paItem.Data);

    case paItem.Code of
      PO_SIM_RENDERER_SHOW : begin
         Form := TProcessingForm(list.Parameters[1]).Form;
         StatisticPath := TString(list.Parameters[0]).String_;
         form1 := TformSimulation.Create(nil);
         aEditorFrame := form1.TfEditor1;
         aEditorFrame.Manager := self;
         aEditorProgress := form1.frmProgress;
         aGUI.Free;
         aGUI := TSimGUI.create(nil,aEditorFrame,aEditorProgress.pgbReplication, aEditorProgress.lblTime);
         form1.Show;
         aLevel := TMasterManager(Master).SceneManager.Scene.Levels[0];
         aEditorProgress.lblTime.Caption := '';
         show;
      end;

      PO_SIM_RENDERER_START : begin start; end;
      PO_SIM_RENDERER_STOP : begin stop; end;
      PO_SIM_RENDERER_PAUSE : begin pause; end;
      PO_SIM_RENDERER_CLOSE : begin ; end;
      PO_SIM_RENDERER_INC_TIME : begin aGUI.IncTime; end;
      PO_SIM_RENDERER_DEC_TIME : begin aGUI.DecTime; end;
      PO_SIM_RENDERER_INC_PERIOD : begin aGUI.IncEvery; end;
      PO_SIM_RENDERER_DEC_PERIOD : begin aGUI.DecEvery; end;
      PO_SIM_RENDERER_ENABLE_OUTPUT : begin aGUI.Vypisovat := true; end;
      PO_SIM_RENDERER_DISABLE_OUTPUT : begin aGUI.Vypisovat := false; end;


      else raise ESimulationRenderer.Create('not specified operation for TEditoLLManager : ' + IntToStr(paItem.Code));
    end;

    if (ret)
      then begin
        if (suc)
          then Result := TProcessItem.create(PO_SUCCESS, nil)
          else Result := TProcessItem.create(PO_FAILURE, nil);
      end else Result := nil;
end;

procedure TSimulationRenderer.show;
var
   log : TLogicalEntity;
   phs : TPhysicalEntity;
   obst: TPolygonObstacle;
   pp: TPathPoint;
   j : integer;
   coord : TCoordinates;
begin
   for phs in aLevel.allObstacles do
    begin
      if phs is TPolygon then
       begin
         obst := TPolygonObstacle.Create;
         for j := 0 to TPolygon(phs).Points.Count - 1 do
         begin
           coord := TCoordinates(TPolygon(phs).Points[j]);
           obst.AddPoint(TVector3f.Create(coord.x, coord.y, 0));
         end;
       obst.ID := phs.ID;
       if phs.LogicalEntity = nil then
        obst.LogEntity:= false
       else obst.LogEntity:= true;
       coord:= TCoordinates(TPolygon(phs).Position);
       obst.Position:= TVector3f.Create(coord.X, coord.Y, 0);
       aEditorFrame.Obstacles.Add(obst);
       aEditorFrame.AllObstacles.Add(obst);
       end;
    end;

   for log in aLevel.AllLogicalEntities do
   begin
      if log.Shape is TPolygon then
       begin
         obst:= TPolygonObstacle.Create;
            case log.TypeLogic of
             ET_DOOR_TYPE: obst.Color.SetRGBA(0.66, 0.78, 2.23, 0.5);
             ET_WALL_TYPE: obst.Color.SetRGBA(2.51, 0.11, 0.35, 0.5);
             ET_STAIRS_TYPE: obst.Color.SetRGBA(0.28,1.64,0.85, 0.5);
             ET_LIFT_TYPE: obst.Color.SetRGBA(2.42, 2.37, 0.28, 0.5);
             ET_TURNIQUET_TYPE: obst.Color.SetRGBA(1.18, 1.52, 1.36, 0.5);
             ET_SPAWN_TYPE: obst.Color.SetRGBA(2.43, 2.49, 0.21, 0.5);
             ET_SINK_TYPE: obst.Color.SetRGBA(0.65, 0.65, 0.65, 0.5);
             ET_WAYPOINT_TYPE: obst.Color.SetRGBA(0.64, 0, 0.64, 0.5);
            end;
           for j := 0 to TPolygon(log.Shape).Points.Count - 1 do
           begin
             coord:= TCoordinates(TPolygon(log.Shape).Points[j]);
             obst.AddPoint(TVector3f.Create(coord.X, coord.Y, 0));
           end;
           coord:= TCoordinates(TPolygon(log.Shape).Position);
           obst.Position:= TVector3f.Create(coord.X, coord.Y, 0);
           obst.Typ:= log.TypeLogic;
           obst.LogEntity:= true;
           obst.ID:= log.ID;
           aEditorFrame.LogObstacles.Add(obst);
           aEditorFrame.AllObstacles.Add(obst);
      end
   end;
end;


procedure TSimulationRenderer.start;
var
  item: TProcessItem;
  prop: String;
//  properties: TRunPropertiesManager.TRunPropertiesType;
  level: TLevel;
  arr : TArrivalsManager.TArrivalType;
begin
  for level in (form as TfrmMain).Master.SceneManager.Scene.Levels do level.getCellularWorld(level.CellSize, level.CellSize, 1);
  aEditorFrame.Level := (form as TfrmMain).Master.SceneManager.Scene.Levels[0];

  item := (Form as TfrmMain).Master.ProcessObject(TProcessItem.create(PO_TREE_GET_CHECKED,nil));
  prop := (item.Data as TConfignData).RunConfig;

  //nastavenie gui pre vypocty
  aEditorProgress.pgbCalc.Min := 0;
  aEditorProgress.pgbCalc.Max := (Form as TfrmMain).Master.ArrivalsManager.Arrivals.Count;
  aEditorProgress.pgbCalc.Position := 0;

  for arr in (Form as TfrmMain).Master.ArrivalsManager.Arrivals do
  begin
    // misiak(no co, miso robi simulaciu, treba nas odlisit tu :D), nahazujem sem nejake napojenie na GUI
    // nech user vidi, co sa deje a nekuka ako maly dede na hamsika
    aEditorProgress.lblTime.Caption := calculating + arr.Name;
    aEditorProgress.pgbCalc.Position := aEditorProgress.pgbCalc.Position + 1;
    Application.ProcessMessages;
    if arr.PedType = atBA then
    begin
      if (item.Data as TConfignData).Arrivals.indexOf(arr.Name) <> -1 then
      begin
        // + kontrola ci neposielam viac rovnakych ciest
        // + ktory lelvel tam davat ?, hadzem tam zatial len prvy
        SetMatrixes((form as TfrmMain).Master.SceneManager.Scene.Levels[0].CellWorld, arr.Path);
      end;
    end;
  end;

  item := (Form as TfrmMain).Master.ProcessObject(TProcessItem.create(PO_RUNPROPMAN_GET_RUN_PROPERTIES,TString.Create(prop)));
  properties := item.Data as TRunPropertiesManager.TRunPropertiesType;

  //nastavenie GUI pre zvysok
  aEditorProgress.pgbReplication.Min := 0;
  aEditorProgress.pgbSimulation.Min := 0;
  aEditorProgress.pgbReplication.Max := Round(properties.Length);
  aEditorProgress.pgbSimulation.Max := Round(properties.Replications);
  aEditorProgress.pgbReplication.Position := 0;
  aEditorProgress.pgbSimulation.Position := 0;

  randomize;
  aEditorFrame.Start := true;
 (Form as TfrmMain).StatisticsCompute.Enabled := true;
  aStarted := true;  aPause := false;  Simulation := TPedSimulation.Create((Form as TfrmMain).Master.SceneManager.Scene,                                      (Form as TfrmMain).Master.ArrivalsManager.Arrivals,
                                       properties,SimGUI);  actRep := 0;  (Form as TfrmMain).Master.ProcessObject(TProcessItem.create(PO_ARRMAN_ACTIVATE,nil));  if not DirectoryExists(StatisticPath + '\replication' + IntToStr(actRep))
    then MkDir(StatisticPath + '\replication' + IntToStr(actRep));
  Simulation.StatisticDir := StatisticPath + '\replication' + IntToStr(actRep);
  Simulation.prepareStatFiles(properties.Stats, TStatisticProcessor.getStatisticTypes);

  DoSomeSimulation;
end;

procedure TSimulationRenderer.stop;
begin
  aSimulation.StopSim;
  aStop := true;
end;

constructor TSimulationRenderer.create(paMaster: TManager);
begin
  inherited Create(paMaster);
  aName := 'none';
  aGUI := nil;
  aPause := false;
  aStop := false;
  aStarted := false;
end;

end.
